package gui;

import java.util.ArrayList;

import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.border.TitledBorder;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeSelectionModel;

import main.Input;
import main.Terminal;
import model.Cinema;
import model.Movie;
import model.ShowTime;
import controller.CtrSale;
import controller.StatusSeat;
import controller.StatusSeat.STATUS;
import database.DBSeat;

public class XListItemPanel extends JPanel
{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private JTextField txtAvailableSeats;
	private JTextField txtCinemaNumber;
	private JTree tree;
	
	private boolean boostTestSpeed;
	
	private UISale parent;

	//build panel
	public XListItemPanel(UISale uiSale, ArrayList<ShowTime> showTimes)
	{
		parent  = uiSale;
		//TODO make this true for faster debugging / testing!
		boostTestSpeed = false;
		
		//these should be the same for all showtimes, therefore the first is selected:
		Movie movie = showTimes.get(0).getMovie();
		Cinema cinema = showTimes.get(0).getCinema();
		
		setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), movie.getTitle(), TitledBorder.LEADING, TitledBorder.TOP, null, null));
		setBounds(210, 63, 350, 310);
		setLayout(null);
		
		JLabel lblDesc = new JLabel("Beskrivelse");
		lblDesc.setBounds(10, 11, 67, 14);
		add(lblDesc);
		
		JTextArea txtrSomeDescription = new JTextArea();
		txtrSomeDescription.setText(movie.getDescription());
		txtrSomeDescription.setBounds(10, 36, 144, 93);
		add(txtrSomeDescription);
		
		JLabel lblCinema = new JLabel("Cinema #");
		lblCinema.setBounds(164, 14, 60, 14);
		add(lblCinema);
		
		txtCinemaNumber = new JTextField();
		txtCinemaNumber.setHorizontalAlignment(SwingConstants.RIGHT);
		txtCinemaNumber.setText(cinema.getNumber());
		txtCinemaNumber.setBounds(255, 11, 38, 20);
		txtCinemaNumber.setEditable(false);
		add(txtCinemaNumber);
		txtCinemaNumber.setColumns(10);
		
		JLabel lblShows = new JLabel("Forestillinger");
		lblShows.setBounds(164, 44, 87, 14);
		add(lblShows);
	
		JLabel lblAvailableSeats = new JLabel("Ledige s\u00E6der");
		lblAvailableSeats.setBounds(10, 191, 100, 14);
		add(lblAvailableSeats);
		
		txtAvailableSeats = new JTextField();
		txtAvailableSeats.setText("??");
		txtAvailableSeats.setEditable(false);
		txtAvailableSeats.setBounds(10, 210, 54, 20);
		add(txtAvailableSeats);
		txtAvailableSeats.setColumns(10);
		
		tree = new JTree();	//needs to be final so button can access it
		tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
		tree.setRootVisible(false);
		tree.setModel(new DefaultTreeModel(new CustomNodeModel(showTimes)));
		tree.setBounds(164, 69, 127, 136);
		tree.addTreeSelectionListener(new TreeSelectionListener() {
			
			@Override
			public void valueChanged(TreeSelectionEvent event) {
				//change the value of node-dependent txt-fields:
				
				CustomNodeModel selectedNode = null;
				
				try  {
					selectedNode = (CustomNodeModel) tree.getLastSelectedPathComponent();
				}
				catch(Exception e) {
					Terminal.say("last selected path component was NOT a CustomModelNode!", e);
				}
				if(selectedNode != null) {
					String cinemaNumber = selectedNode.getCinemaNumber();
					if(cinemaNumber != null) {
						txtCinemaNumber.setText(cinemaNumber);
					}
					else {
						txtCinemaNumber.setText("");
					}
					
					int availableSeats = selectedNode.getNumberOfAvailableSeats();
					if(availableSeats >= 0) {
						txtAvailableSeats.setText("" + availableSeats);
					}
					else {
						txtAvailableSeats.setText("");
					}
					
					parent.setSelectedShowTime(selectedNode.getCurrentShowTime());
				}
				else {
					txtCinemaNumber.setText("");
					txtAvailableSeats.setText("");
				}
				
			}
		});
		
		//add KeyListener (when it is initialized)
		Input.addInputListenerWhenInitialized(tree);
		
		add(tree);
		
		JCheckBox chckbxIs3Dx = new JCheckBox("3D");
		chckbxIs3Dx.setSelected(movie.is3D());
		chckbxIs3Dx.setBounds(10, 143, 97, 23);
		chckbxIs3Dx.setEnabled(false);
		add(chckbxIs3Dx);
	}
	
	public JTree getTree()
	{
		return tree;
	}
	
	public void setAvailableSeats(int seats)
	{
		txtAvailableSeats.setText("" + seats);
	}
	
	//UI sale needs access to this data type as well
	public class CustomNodeModel extends DefaultMutableTreeNode
	{
		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		private String strDateTime; //stores information depending on it being a date-node or a time-node
		private ArrayList<ShowTime> movie;	//from root constructor
		private ShowTime currentShowTime;	//from time constructor
		private int numberOfAvailableSeats; //stores information about available seats (when last loaded) for time-node
		private int numberOfSeatsInCinema; //stores the number of seats for this cinema. Used by Root-constructor.
		private String cinemaNumber;
	
		//Root constructor
		public CustomNodeModel(ArrayList<ShowTime> movie) 
		{
			this.movie = movie;
			
			//"Error" codes:
			strDateTime = "-1"; 
			currentShowTime = null; 
			numberOfAvailableSeats = -1;
			numberOfSeatsInCinema = -1;
			cinemaNumber = "-1";
			
			ArrayList<CustomNodeModel> loadedDates = new ArrayList<CustomNodeModel>();
			
			//TODO Debug statement begin:
//			if(! boostTestSpeed) {
//				numberOfSeatsInCinema =  new DBSeat().getAllSeats(movie.get(0).getCinema().getNumber()).size();
//			}
			// Debug statement END
			
			for(ShowTime st : movie) {
				
				//is this showtimes date already loaded?
				CustomNodeModel date = new CustomNodeModel(st.getDate());
				
				if(loadedDates.contains(date)) {
					loadedDates.get(loadedDates.indexOf(date)).add(date);
				}
				else {
					String startTime = String.format("%d:%d", st.getHour(), st.getMinute());
					String endTime = getEndTime(st.getHour(), st.getMinute(), st.getMovie().getLenght());
					date.add(new CustomNodeModel(startTime, endTime, st));
					loadedDates.add(date);
				}
			}
			
			//display loaded items
			for(CustomNodeModel date : loadedDates) {
				add(date);
			}
		}
		
		//Date constructor
		public CustomNodeModel(String strDate)
		{
			super(strDate);
			this.strDateTime = strDate;
		}
		
		//Time constructor
		public CustomNodeModel(String startTime, String endTime, ShowTime currentShowTime)
		{
			super(startTime + " -- " + endTime);
			strDateTime = startTime + " -- " + endTime;
			this.currentShowTime = currentShowTime;
			
			cinemaNumber = currentShowTime.getCinema().getNumber();
			//TODO Debug statement begin:
			if(!boostTestSpeed) {
				numberOfAvailableSeats = 0; 
				
				ArrayList<StatusSeat> ss = new CtrSale().findSeats(currentShowTime);
				for(StatusSeat statSeat : ss) {
					if(statSeat.getStatus() == STATUS.FREE) {
						numberOfAvailableSeats++;
					}
				}
			}
			// Debug statement END
		}
		
		public int getNumberOfAvailableSeats()
		{
			return numberOfAvailableSeats;
		}
		
		public String getCinemaNumber()
		{
			return cinemaNumber;
		}
		
		/**
		 * Returns which ArrayList<ShowTime> was parsed to this instance of CustomNodeModel
		 * @return ArrayList<ShowTime>, all of them with the same movie
		 */
		public ArrayList<ShowTime> getMovie()
		{
			return movie;
		}
		
		public ShowTime getCurrentShowTime()
		{
			return currentShowTime;
		}
		
		public String getStrDateTime()
		{
			return strDateTime;
		}
		
		/**
		 * Returns weather the parsed CustomNodeModel's (parsed from obj) strDate equals this strDate <b>if</b>
		 * the parameter is a CustomNodeModel. Else, returns false.
		 */
		@Override
		public boolean equals(Object obj) 
		{
			try {
				CustomNodeModel otherNode = (CustomNodeModel) obj;
				return otherNode.getStrDateTime().equals(strDateTime);
			}
			catch(Exception e)
			{
				Terminal.say(obj + " is not a CustomNodeModel-object!", e);
			}
			return false;
		}
		
		
		private String getEndTime(int startHour, int startMinute, int length)
		{
			int newMinute = startMinute + length;
			int newHour = startHour;
			
			while(newMinute >= 60) {
				newHour++;
				if(newHour >= 24) {
					newHour -= 24;
				}
				newMinute -= 60;
			}
			
			String endHour = new String();
			if(newHour < 10) {
				endHour = "0" + newHour;
			}
			else {
				endHour = "" + newHour;
			}
			
			String endMinute = new String();
			if(newMinute < 10) {
				endMinute = "0" + newMinute;
			}
			else {
				endMinute = "" + newMinute;
			}
			return endHour + ":" + endMinute;
		}
	}
}
